package org.gavin.core.advice;

import ch.qos.logback.core.status.Status;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.gavin.core.domain.R;
import org.gavin.core.enums.CommonStatus;
import org.gavin.core.exception.*;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.Set;

/**
 * ResponseExceptionAdvice
 *
 * @author grl
 * @date 2024/1/4
 */
@Slf4j
@ResponseBody
@ControllerAdvice
@RequiredArgsConstructor
public class ResponseExceptionAdvice {


    @ExceptionHandler(value = ParamException.class)
    public R paramExceptionHandler(ParamException e) {
        log.error("Param Exception: {} {} {}", e.getModule(), e.getMsg(), e.getArgs(), e);
        return R.fail(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(value = IllegalArgumentException.class)
    public R IllegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error("Param Exception:", e);
        return R.fail(CommonStatus.PARAM_ERROR.getCode(), e.getMessage());
    }

    /**
     * 对方法参数校验异常处理方法(仅对于表单提交有效，对于以json格式提交将会失效)
     * 如果是表单类型的提交，则spring会采用表单数据的处理类进行处理（进行参数校验错误时会抛出BindException异常）
     */
    @ExceptionHandler(BindException.class)
    public R handlerBindException(BindException e) {
        log.error("Param Exception:", e);
        return R.fail(CommonStatus.PARAM_ERROR.getCode(), e.getMessage());
    }

    /**
     * 对方法参数校验异常处理方法(前端提交的方式为json格式出现异常时会被该异常类处理)
     * json格式提交时，spring会采用json数据的数据转换器进行处理（进行参数校验时错误是抛出MethodArgumentNotValidException异常）
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R validExceptionHandler(MethodArgumentNotValidException e) {
        log.error("Param Exception:", e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        return R.fail(CommonStatus.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
    }

    /**
     * 对方法参数校验异常处理方法(前端提交的方式: 参数直接在请求路径中，出现异常时会被该异常类处理)
     * 例子：http://192.168.6.29:8089/ccbf/getCcbflifeUp?waltId=sdgsgs
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public R constraintViolationExceptionHandler(ConstraintViolationException e) {
        log.error("Violation Exception:", e);
        String errorInfo = "";
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> item : violations) {
            errorInfo = StringUtils.isNotBlank(errorInfo) ? errorInfo + "," : "";
            errorInfo = errorInfo + item.getMessage();
        }
        return R.fail(CommonStatus.PARAM_ERROR.getCode(), errorInfo);
    }

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public R httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
        log.error("JSON format Exception:", e);
        return R.fail(CommonStatus.JSON_ERROR);
    }

    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    public R HttpMediaTypeNotSupportedExceptionHandler(HttpMediaTypeNotSupportedException e) {
        log.error("Request format Exception:", e);
        return R.fail(CommonStatus.REQUEST_FORMAT_ERROR);
    }

    @ExceptionHandler(value = DataException.class)
    public R dataExceptionExceptionHandler(DataException e) {
        log.error("dataExceptionExceptionHandler:", e);
        Integer code = e.getCode();
        String msg = e.getMsg();
        return R.fail(code, msg);
    }

    @ExceptionHandler(value = MissingRequestHeaderException.class)
    public R missingRequestExceptionHandler(MissingRequestHeaderException e){
        log.error("请求缺少参数异常!", e);
        return R.fail(CommonStatus.PARAM_ERROR);
    }

    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public R httpNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        log.error("Request method not supported：", e);
        return R.fail(CommonStatus.REQUEST_NOT_SUPPORT_ERROR);
    }

    @ExceptionHandler(value = NoHandlerFoundException.class)
    public R noHandlerFoundExceptionHandler(NoHandlerFoundException e) {
        return R.fail(CommonStatus.NO_HANDLER_FOUND_ERROR);
    }

    @ExceptionHandler(value = ConfigException.class)
    public R configExceptionHandler(ConfigException e) {
        log.error("Config  Exception 错误 model： {}  请求头中 safetyAppId ： {}：", e.getModule(), e.getArgs(), e);
        return R.fail(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = SafetyException.class)
    public R safetyExceptionHandler(SafetyException e) {
        log.error("加解密实现类异常 Exception 错误 model： {}  请求头中密文类型参数 ： {}：", e.getModule(), e.getArgs(), e);
        return R.fail(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = AccessException.class)
    public R accessExceptionHandler(AccessException e) {
        log.error("访问限制实现类异常 Exception 错误 调用方法： {}", e.getModule(), e);
        return R.fail(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = JsonConvertException.class)
    public R jsonConvertExceptionHandler(JsonConvertException e){
        log.error("Json 转换异常 Exception 错误 调用方法： {}", e.getModule(), e);
        return R.fail(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(value = Exception.class)
    public R exceptionHandler(Exception e) {
        log.error("Global Exception：", e);
        return R.fail(CommonStatus.fail);
    }
}
